home *** CD-ROM | disk | FTP | other *** search
- /* Length.C
- *
- * The official LaTeX length parameters are implemented here. They control
- * variables such as the paragraph indentation and the space to skip between
- * lines.
- *
- * Copyright 1992 Jonathan Monsarrat. Permission given to freely distribute,
- * edit and use as long as this copyright statement remains intact.
- *
- */
-
- #include "Global.h"
- #include "Font.h"
- #include <string.h>
- #include <search.h>
- #include <stdlib.h>
- #include <stdio.h>
-
- LengthParam::LengthParam(LengthParam *lp, Length *parent)
- {
- _value = lp->_value;
- _tokentext = lp->_tokentext;
- _parent = parent;
- }
-
- LengthParam::LengthParam(float value, char *tokentext, Length *parent)
- {
- _value = value;
- _tokentext = new char [strlen(tokentext)+1];
- strcpy(_tokentext,tokentext);
- _parent = parent;
- }
-
- LengthParam::~LengthParam()
- {
- delete _tokentext;
- }
-
- int LengthParam::compare(const void *length1, const void *length2)
- {
- LengthParam **len1;
- LengthParam **len2;
-
- len1 = (LengthParam **) length1;
- len2 = (LengthParam **) length2;
-
- return strcmp((*len1)->_tokentext, (*len2)->_tokentext);
- }
-
- void LengthParam::set(float value)
- {
- if(_value != value) {
- if(value > _value && match("\\baselineskip"))
- Global::files->readjust_vspace = value;
- _value = value;
- postscript_set();
- }
- }
-
- float LengthParam::get()
- {
- return _value;
- }
-
- void LengthParam::revert(Length *from)
- {
- LengthParam **lp;
- lp = from->fetch(_tokentext);
- if(_value != (*lp)->get())
- postscript_set();
- }
-
- void LengthParam::postscript_set()
- {
- LengthParam **lp;
- Global::files->outfile << endl;
-
- if(match("\\baselineskip"))
- Global::files->outfile << _value << " BASELINESKIP" << endl;
- else if(match("\\parindent"))
- Global::files->outfile << "/parindent " << _value << " def" << endl;
- else if(match("\\parskip"))
- Global::files->outfile << "/parskip " << _value << " def" << endl;
- else if(match("\\textheight")) {
- lp = _parent->fetch("\\topmargin");
- Global::files->outfile << "/bottommargin "
- << 684.0 - _value - (*lp)->get() << " def" << endl;
- }
- else if(match("\\textwidth") || match("\\linewidth")) {
- lp = _parent->fetch("\\oddsidemargin");
- Global::files->outfile << "/rightmargin "
- << 540.0 - _value - (*lp)->get() << " def" << endl;
- }
- else if(match("\\topmargin")) {
- Global::files->outfile << "/topmargin " << _value+108 << " def" << endl;
- lp = _parent->fetch("\\textheight");
- Global::files->outfile << "/bottommargin "
- << 684.0 - _value - (*lp)->get() << " def" << endl;
- }
- else if(match("\\oddsidemargin") || match("\\evensidemargin")) {
- Global::files->outfile << "/leftmargin " << _value+72 << " def" << endl;
- lp = _parent->fetch("\\textwidth");
- Global::files->outfile << "/rightmargin "
- << 540.0 - _value - (*lp)->get() << " def" << endl;
- }
- }
-
- int LengthParam::match(char *tokentext)
- {
- return !strcmp(_tokentext,tokentext);
- }
-
- Length::Length()
- {
- /* The LaTeX defaults for the LaTeX Length Parameters */
- numvalues = 0;
- makeparam( 12.0, "\\baselineskip"); // space between lines
- makeparam( 1.0, "\\baselinestretch"); // ditto, in units of lines
- makeparam(126.0, "\\linewidth"); // same as textwidth
- makeparam( 18.0, "\\parindent"); // paragraph indentation
- makeparam( 0.0, "\\parskip"); // space between paragraphs
- makeparam(540.0, "\\textheight"); // height of the page
- makeparam(360.0, "\\textwidth"); // width of the page
- makeparam( 54.0, "\\topmargin"); // top margin
- makeparam( 54.0, "\\oddsidemargin"); // left margin, basically
- makeparam( 54.0, "\\evensidemargin"); // left margin, basically
- makeparam( 21.4, "\\bigskipamount"); // big vertical skip
- makeparam( 16.9, "\\medskipamount"); // medium vertical skip
- makeparam( 14.5, "\\smallskipamount"); // small vertical skip
- makeparam( 28.34,"cm"); // centimeters (28 pts)
- makeparam( 10.0, "em"); // width of letter M in current font
- makeparam( 8.0, "ex"); // width of letter X in current font
- makeparam( 72.0, "in"); // inches (72 pts)
- makeparam( 12.0, "pc"); // Picas (1pc = 12pt)
- makeparam( 1.0, "pt"); // Points
- makeparam( 2.83,"mm"); // millimeters
- for(int x=0; x < numvalues; x++) // Initialize the variables
- postscript_set(x);
- }
-
- /* The class Length contains an array of pointers. The automatic definition
- * created by the C++ compiler just copies over these pointers to the new
- * Length. But we want the new Length being created to actually have copies
- * of all the LengthParams in *values[], not pointers to the same ones!
- * So an explicit definition is written here.
- */
- Length::Length(Length *base)
- {
- numvalues = base->numvalues;
- for(int index=0; index < numvalues; index++)
- values[index] = new LengthParam(base->values[index], this);
- }
-
- Length::~Length()
- {
- for(int x=0; x < numvalues; x++)
- delete values[x];
- }
-
- Param *Length::copy()
- {
- return new Length(this);
- }
-
- // Fetches the LengthParam in array values with given name
- LengthParam **Length::fetch(char *tokenstr)
- {
- LengthParam key(0.0, tokenstr, this);
- LengthParam *keyptr = &key;
- LengthParam **keyptrptr = &keyptr;
- LengthParam **lp = (LengthParam **)
- bsearch((char *)keyptrptr, (char *) values,
- numvalues, sizeof(LengthParam *), LengthParam::compare);
- return lp;
- }
-
- void Length::makeparam(float value, char *tokentext)
- {
- values[numvalues++] = new LengthParam(value, tokentext, this);
- qsort((char*)values, numvalues,
- sizeof(LengthParam *), LengthParam::compare);
- }
-
- void Length::set_lp(LengthParam *lp, float value)
- {
- LengthParam **skip;
- lp->set(value);
- if(lp->match("\\baselinestretch")) {
- skip = fetch("\\baselineskip");
- float fontsize = Stack::get(Environment::PFont, Font::Size, "");
- (*skip)->set(value * fontsize * 1.2); // 1.2 is magic spacing number
- } else if(lp->match("\\oddsidemargin")) {
- skip = fetch("\\evensidemargin");
- (*skip)->set(value);
- } else if(lp->match("\\evensidemargin")) {
- skip = fetch("\\oddsidemargin");
- (*skip)->set(value);
- }
- }
-
- // Set the value of the LengthParam in the values array with given name
- // to the given value. Returns success boolean.
- int Length::set(int, float value, char *tokentext)
- {
- LengthParam **lp;
- if((lp=fetch(tokentext)) == NULL)
- return FALSE;
-
- set_lp(*lp,value);
- return TRUE;
- }
-
- float Length::get(int subtype, char *tokentext)
- {
- if(subtype == Parse_Length)
- return length_argument();
-
- LengthParam **lp; // Get parameter value
- if((lp=fetch(tokentext)) == NULL) {
- char message[MAXSTRING];
- sprintf(message, "No length parameter %s defined", tokentext);
- Global::files->fatal_error(message);
- }
- return (*lp)->get();
- }
-
- void Length::postscript_set(int index)
- {
- values[index]->postscript_set();
- }
-
- void Length::revert(Param *from)
- {
- for(int index=0; index < numvalues; index++)
- values[index]->revert((Length *)from);
- }
-
- /* Parses an argument between braces to be used in a length function
- * such as \addtolength and \setlength. Returns the length in points.
- */
- float Length::length_argument()
- {
- char *tokenname;
- LengthParam **lp;
- float val = 1.0;
- Global::files->set_parsing_length(TRUE);
- for(Token command; !command.match("}"); command = Token()) {
- if(command.match(""))
- continue;
- tokenname = command.get_text();
- if(tokenname[0] >= '0' && tokenname[0] <= '9'
- || tokenname[0]=='-' || tokenname[0]=='.') {
- float t; // A number
- sscanf(tokenname,"%f",&t);
- val *= t;
- } else { // A variable
- lp = fetch(tokenname);
- if(!lp) {
- char message[MAXSTRING];
- sprintf(message, "Undefined length parameter %s", tokenname);
- Global::files->fatal_error(message);
- }
- val *= (*lp)->get();
- }
- }
-
- Global::files->set_parsing_length(FALSE);
- return val;
- }
-
- void Length::addtolength(int, int, float, char *)
- {
- Token openbrace;
- if(!openbrace.match("{"))
- Global::files->fatal_error(
- "Expecting '{' after \\addtolength statement");
-
- Token lengthparam;
- if(lengthparam.match("}"))
- Global::files->fatal_error(
- "Expecting lengthparam before closing '}' in \\addtolength");
-
- LengthParam **lp = fetch(lengthparam.get_text());
-
- Token closebrace;
- if(!closebrace.match("}"))
- Global::files->fatal_error(
- "More than one word before closing '}' in \\addtolength");
-
- openbrace = Token();
- if(!openbrace.match("{"))
- Global::files->fatal_error(
- "Expecting second '{' after \\addtolength statement");
-
- set_lp(*lp,(*lp)->get()+Length::length_argument());
- }
-
- void Length::newlength(int, int, float, char *)
- {
- Token openbrace;
- if(!openbrace.match("{"))
- Global::files->fatal_error("Expecting '{' after \\newlength statement");
-
- Token lengthparam;
- if(lengthparam.match("}"))
- Global::files->fatal_error(
- "Expecting lengthparam before closing '}' in \\newlength");
-
- makeparam(0.0,lengthparam.get_text());
-
- Token closebrace;
- if(!closebrace.match("}"))
- Global::files->fatal_error(
- "More than one word before closing '}' in \\newlength");
- }
-
- void Length::setlength(int, int, float, char *)
- {
- Token openbrace;
- if(!openbrace.match("{"))
- Global::files->fatal_error("Expecting '{' after \\setlength statement");
-
- Token lengthparam;
- if(lengthparam.match("}"))
- Global::files->fatal_error(
- "Expecting lengthparam before closing '}' in \\setlength");
-
- LengthParam **lp = fetch(lengthparam.get_text());
-
- Token closebrace;
- if(!closebrace.match("}"))
- Global::files->fatal_error(
- "More than one word before closing '}' in \\setlength");
-
- openbrace = Token();
- if(!openbrace.match("{"))
- Global::files->fatal_error(
- "Expecting second '{' after \\setlength statement");
-
- set_lp(*lp,Length::length_argument());
- }
-